iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
自我挑戰組

Lex & Yacc 學習筆記系列 第 5

[Day5] Lex - yyout

  • 分享至 

  • xImage
  •  

本篇內容

  • 介紹自定義變數yyout
  • 介紹自定義變數yyleng
  • 介紹編譯檔案lex.yy.c

介紹

我們昨天有提到,在Lex中,若要把檔案印出到terminal,可以使用預定義的參數ECHO
Lex除了可以讀取檔案外,也有把讀取的文件印出或輸入到檔案的功能喔!

在這裡我們會用到一個變數yyout,它跟yyin屬性一樣,是指向 FILE 物件的指標。
透過下面的例子,我們來看看yyout的用法吧!

範例 - C++程式碼輸出

說明

根據昨天的C++程式碼讀取,我們希望能將非註解的程式碼輸出至txt檔案中。

程式實作

基本上來說,絕大部分都跟昨天的例子一樣,不同的地方在主程式:

int main(void) {
    const char* sFile = "file.cpp";
    const char* oFile = "output.cpp";
    FILE* fp = fopen(sFile, "r");
    if (fp == NULL) {
        printf("cannot open %s\n", sFile);
        return -1;
    }
    extern FILE* yyin, *yyout;
    yyin = fp;
    yyout = fopen(oFile, "w");
    yylex();
    return 0;
}

在這裡,我們定義yyout並指定輸出的檔案名稱,再執行檔案的parser。

這裡出現了一個問題:ECHO函式沒有被更改,為什麼輸出路徑就變了呢?

初探lex.yy.c

這個問題的答案就藏在編譯過程中生出的lex.yy.c檔案。裡面詳細記錄了轉成C語言的相關函式與變數。我們來看看跟ECHO函式有關的部分

#ifndef ECHO
/* This used to be an fputs(), but since the string might contain NUL's,
 * we now use fwrite().
 */
#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
#endif

看到這裡,我們便可以知道ECHO函式背後的真面目 - 其實就只是C語言的輸出函式而已!
這邊稍微解釋一下新出現的變數 - yyleng。它是目前讀取到的字串yytext的長度。
因此,我們只要先定義好yyout,就可以決定要把文字輸出到哪裡。

除了ECHO以外,lex檔案中許多變數其實都可以自己更改定義或相關參數,改完後只要到lex.yy.c就可以檢查自己的設定是否正確。

完整程式碼

%{
    int yylex(void);
%}

%x COMMENT

%%

\/\/              { BEGIN COMMENT; }
<COMMENT>[^\n]*   { ; }
<COMMENT>\n       { BEGIN 0; ECHO; }

.|\n              { ECHO; }

%%

int yywrap(void) {
    return 1;
}

int main(void) {
    const char* sFile = "file.cpp";
    const char* oFile = "output.cpp";
    FILE* fp = fopen(sFile, "r");
    if (fp == NULL) {
        printf("cannot open %s\n", sFile);
        return -1;
    }
    extern FILE* yyin, *yyout;
    yyin = fp;
    yyout = fopen(oFile, "w");
    yylex();
    return 0;
}

執行結果

輸入內容(file.cpp)

#include <cstdio>

int main() {
    int age = 100;  // Input user's age
    char* name = "BarleyTea";   // Input user's name
    printf("Hi, my name is %s. I am %d years old.\n", name, age);   // print user info
}

輸出結果(output.cpp)

#include <cstdio>

int main() {
    int age = 100;
    char* name = "BarleyTea";
    printf("Hi, my name is %s. I am %d years old.\n", name, age);
}

結語

透過更改yyout的方式,可以將文字輸出到指定的外部檔案。

此外,在lex.yy.c檔案中,有多項參數可以自行定義或調整。

參考資料

  • Levine, John R., Tony Mason and Doug Brown [1992]. Lex & Yacc. O’Reilly & Associates, Inc. Sebastopol, California.

上一篇
[Day4] Lex - State
下一篇
[Day6] Lex - yywrap
系列文
Lex & Yacc 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言